package com.cloudkinto.service.sc.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.ScOverInfoRuleDao;
import com.cloudkinto.dao.ScOverRuleDao;
import com.cloudkinto.dao.UserDao;
import com.cloudkinto.entity.ScOverInfoRuleDo;
import com.cloudkinto.entity.ScOverRuleDo;
import com.cloudkinto.entity.UserDo;
import com.cloudkinto.service.sc.ScOverInfoRuleService;
import com.cloudkinto.service.sc.ScOverRuleService;
import com.cloudkinto.utils.BeanCopierUtils;
import com.cloudkinto.vo.sc.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author hua
 * @since 2024-11-05
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class ScOverRuleServiceImpl extends ServiceImpl<ScOverRuleDao, ScOverRuleDo> implements ScOverRuleService {
    @Autowired
    private ScOverRuleDao dao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private ScOverInfoRuleService scOverInfoRuleService;
    @Autowired
    private ScOverInfoRuleDao scOverInfoRuleDao;

    @Override
    public SingleResult addInit() {
        return SingleResult.success("");
    }

    @Override
    public Object add(ScRuleAddReq req, Long userId, Long tenantId) {
        this.check(req, null, tenantId);
        ScOverRuleDo entityDo = new ScOverRuleDo();
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setCreateBy(userId);
        entityDo.setTenantId(tenantId);
        entityDo.setDeleteFlag(0);
        dao.insert(entityDo);
        this.insertChild(req.getList(), entityDo.getId());
        return entityDo.getId();
    }

    public void insertChild(List<List<ScRuleInfoAddReq>> listList, Long overId) {
        //插入子表
        for (List<ScRuleInfoAddReq> list : listList) {
            Long parentId = -1L;
            for (ScRuleInfoAddReq add : list) {
                ScOverInfoRuleDo rule = new ScOverInfoRuleDo();
                BeanUtils.copyProperties(add, rule);
                rule.setParentId(parentId);
                rule.setSurchargeRuleId(overId);
                rule.setOverId(overId);
                scOverInfoRuleDao.insert(rule);
                if (parentId == -1L) parentId = rule.getId();
            }
        }
    }

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    public void check(ScRuleEt et, Long id, Long tenantId) {
        if (StringUtils.isBlank(et.getSurchargeName())) throw new BizException(SysConstant.ScOverRule_Add_Name_Empty);
        ScOverRuleDo ruleDo = dao.selectOne(new LambdaQueryWrapper<ScOverRuleDo>().eq(ScOverRuleDo::getSurchargeName, et.getSurchargeName()).eq(ScOverRuleDo::getTenantId, tenantId)
                .ne(id != null, ScOverRuleDo::getId, id));
        if (ruleDo != null) throw new BizException(SysConstant.ScOverRule_Add_Name_Same);
    }

    @Override
    public Object update(ScRuleUpdateReq req, Long userId, Long tenantId) {
        this.check(req, req.getId(), tenantId);
        ScOverRuleDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        entityDo.setUpdateBy(userId);
        dao.updateById(entityDo);
        //子表
        scOverInfoRuleDao.delete(new LambdaQueryWrapper<ScOverInfoRuleDo>().eq(ScOverInfoRuleDo::getOverId, req.getId()));
        this.insertChild(req.getList(), entityDo.getId());
        return entityDo.getId();
    }

    @Override
    public int delete(Long id, Long userId, Long tenantId) {
        int count = dao.getUsedCount(id, tenantId);
        if (count > 0) throw new BizException(SysConstant.Rule_HadUsed);
        ScOverRuleDo entityDo = dao.selectById(id);
        handlerDeleteBefore(entityDo, userId);
        dao.updateById(entityDo);
        scOverInfoRuleDao.updateDelete(id, userId);
//        scOverInfoRuleDao.delete(new LambdaQueryWrapper<ScOverInfoRuleDo>().eq(ScOverInfoRuleDo::getOverId, id));
        return dao.deleteById(id);
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(ScOverRuleDo entityDo, Long userId) {
        entityDo.setDeleteBy(userId);
        entityDo.setDeleteTime(new Date());
    }

    @Override
    public Object detail(Long id) {
        if (id == null) return null;
        Map<String, String> map = new HashMap<>();
        map.put("id", id + "");
        List<ScRulePageRes> pageList = this.getList(map);
        if (pageList.isEmpty()) throw new BizException(SysConstant.No_Data);
        ScRuleDetailRes res = new ScRuleDetailRes();
        BeanUtils.copyProperties(pageList.get(0), res);
        //获取子表 List
        List<ScOverInfoRuleDo> list = scOverInfoRuleService.list(new LambdaQueryWrapper<ScOverInfoRuleDo>()
                .eq(ScOverInfoRuleDo::getOverId, id));
        List<ScRuleInfoUpdateReq> info = BeanCopierUtils.listCopyMapper(list, ScOverInfoRuleDo.class, ScRuleInfoUpdateReq.class);
        Map<Long, List<ScRuleInfoUpdateReq>> collect = info.stream().collect(Collectors.groupingBy(ScRuleInfoUpdateReq::getParentId));

        List<List<ScRuleInfoUpdateReq>> l = new ArrayList<>();
        if (collect.get(-1L) != null) {
            for (ScRuleInfoUpdateReq parent : collect.get(-1L)) {
                List<ScRuleInfoUpdateReq> oneList = new ArrayList<>();
                oneList.add(parent);
                if (collect.get(parent.getId()) != null) oneList.addAll(collect.get(parent.getId()));
                l.add(oneList);
            }
        }
        res.setList(l);
        return res;
    }

    //查询明细之后要执行的业务定制处理
    private Object handlerDetailAfter(Object res) {
        return res;
    }

    @Override
    public SingleResult pageInit() {
        Map<String, Object> result = new HashMap<>();
        result.put("operateSign", this.geOperateSign());
        result.put("surchargeType", this.geSurchargeType());
        result.put("calculateType", this.getSc_Calculate_Type());
        result.put("unit", StaticDict.getUnitMeasure());
        result.put("operateSignContain", this.getSignContain());

        return SingleResult.success(result);
    }

    public List<Map<Object, Object>> getSignContain() {
        List<Map<Object, Object>> result = new ArrayList<>();
        for (StaticDict.Rule_Operate_Sign_Contain value : StaticDict.Rule_Operate_Sign_Contain.values()) {
            Map<Object, Object> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getSign());
            result.add(map);
        }
        return result;
    }


//    public List<Map<Object, Object>> getUnitMeasure() {
//        List<Map<Object, Object>> result = new ArrayList<>();
//        for (StaticDict.OMP_UnitMeasurement value : StaticDict.OMP_UnitMeasurement.values()) {
//            Map<Object, Object> map = new HashMap<>();
//            map.put("id", value.getValue());
//            map.put("name", value.getScText());
//            result.add(map);
//        }
//        return result;
//    }


    public List<Map<Object, Object>> getSc_Calculate_Type() {
        List<Map<Object, Object>> result = new ArrayList<>();
        for (StaticDict.Sc_Calculate_Type value : StaticDict.Sc_Calculate_Type.values()) {
            Map<Object, Object> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getText());
            map.put("unitType", value.getUnitType());
            result.add(map);
        }
        return result;
    }

    public List<Map<Object, Object>> geSurchargeType() {
        List<Map<Object, Object>> result = new ArrayList<>();
        for (StaticDict.Surcharge_type value : StaticDict.Surcharge_type.values()) {
            Map<Object, Object> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getText());
            result.add(map);
        }
        return result;
    }

    public List<Map<Object, Object>> geOperateSign() {
        List<Map<Object, Object>> result = new ArrayList<>();
        for (StaticDict.Rule_Operate_Sign value : StaticDict.Rule_Operate_Sign.values()) {
            if (!value.getSource().contains("sc")) continue;
            Map<Object, Object> map = new HashMap<>();
            map.put("id", value.getValue());
            map.put("name", value.getSign());
            result.add(map);
        }
        return result;
    }

    @Override
    public List<ScRulePageRes> getList(Map<String, String> map) {
        QueryWrapper<ScOverRuleDo> wrapper = queryBuild(map);
        List<ScOverRuleDo> list = this.list(wrapper);
        List<ScRulePageRes> result = handlerListAfter(list);
        return result;
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {
        QueryWrapper<ScOverRuleDo> wrapper = queryBuild(map);
        IPage<ScOverRuleDo> page = pageInit(map);
        page = this.page(page, wrapper);
        List<ScRulePageRes> resList = handlerListAfter(page.getRecords());
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    //查询分页列表之后对列表数据的处理
    private List<ScRulePageRes> handlerListAfter(List<ScOverRuleDo> list) {
        List<ScRulePageRes> result = BeanCopierUtils.listCopyMapper(list, ScOverRuleDo.class, ScRulePageRes.class);
        Map<Long, String> userMap = new HashMap<>();
        for (ScRulePageRes res : result) {
            if (res.getCreateBy() != null) {
                if (userMap.get(res.getCreateBy()) == null) {
                    UserDo userDo = userDao.selectById(res.getCreateBy());
                    if (userDo != null) {
                        userMap.put(userDo.getId(), userDo.getUserAccount());
                    }
                }
                res.setCreateByName(userMap.get(res.getCreateBy()));
            }
            if (res.getUpdateBy() == null) continue;
            if (userMap.get(res.getUpdateBy()) == null) {
                UserDo userDo = userDao.selectById(res.getUpdateBy());
                if (userDo == null) continue;
                userMap.put(res.getUpdateBy(), userDo.getUserAccount());
            }

            res.setUpdateByName(userMap.get(res.getUpdateBy()));
        }

        return result;
    }

    private IPage<ScOverRuleDo> pageInit(Map<String, String> map) {
        IPage<ScOverRuleDo> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private QueryWrapper<ScOverRuleDo> queryBuild(Map<String, String> map) {
        QueryWrapper<ScOverRuleDo> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(map.get("surchargeName"))) {
            wrapper.like("surcharge_name", map.get("surchargeName"));
        }
        if (StringUtils.isNotBlank(map.get("status"))) {
            wrapper.eq("status", map.get("status"));
        }
        if (StringUtils.isNotBlank(map.get("surchargeType"))) {
            wrapper.eq("surcharge_type", map.get("surchargeType"));
        }
        if (StringUtils.isNotBlank(map.get("id"))) {
            wrapper.eq("id", map.get("id"));
        }
        if (StringUtils.isNotBlank(map.get("tenantId"))) {
            wrapper.eq("tenant_id", map.get("tenantId"));
        }
        wrapper.orderByDesc("update_time");
        return wrapper;
    }


    @Override
    public boolean trial(SurchargeTrialReq req) {
        ScOverRuleDo entity = dao.selectById(req.getId());
        if (entity == null) return false;
        Float[] size = {req.getLength(), req.getWidth(), req.getHeight()};
        Arrays.sort(size, Comparator.reverseOrder());
        Map<Long, List<ScOverInfoRuleDo>> collect = scOverInfoRuleService.list(new LambdaQueryWrapper<ScOverInfoRuleDo>()
                .eq(ScOverInfoRuleDo::getOverId, req.getId())).stream().collect(Collectors.groupingBy(ScOverInfoRuleDo::getParentId));
        if (collect.isEmpty()) return false;
        if (collect.get(-1L) == null) return false;
        boolean parentFlag = true;
        for (ScOverInfoRuleDo parent : collect.get(-1L)) {
            List<ScOverInfoRuleDo> oneList = new ArrayList<>();
            oneList.add(parent);
            if (collect.get(parent.getId()) != null) oneList.addAll(collect.get(parent.getId()));
            boolean flag = true;
            for (ScOverInfoRuleDo et : oneList) {
                flag = this.jugOneRule(et, size, req, entity.getSizeUnit());
                if (parent.getRuleRelation() == 0) {//并且
                    if (!flag) break;
                } else if (parent.getRuleRelation() == 1) {//或者
                    if (flag) break;
                }
            }
            parentFlag = flag;
            if (entity.getRuleRelation() == 0) {//并且
                if (!parentFlag) break;
            } else if (entity.getRuleRelation() == 1) {//或者
                if (parentFlag) break;
            }

        }
        return parentFlag;
    }


    public boolean jugOneRule(ScOverInfoRuleDo et, Float[] size, SurchargeTrialReq req, String sizeUnit) {
        if (StaticDict.Sc_Calculate_Type.Longest_Side.getValue().equals(et.getCalculateType())) {
            //最长边
            return this.sizeJug(et.getOperateSign(), size[0], et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Second_Longest_Side.getValue().equals(et.getCalculateType())) {
            return this.sizeJug(et.getOperateSign(), size[1], et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Shortest_Size.getValue().equals(et.getCalculateType())) {
            return this.sizeJug(et.getOperateSign(), size[2], et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Fourth.getValue().equals(et.getCalculateType())) {
            return this.sizeJug(et.getOperateSign(), size[0] + 2 * (size[1] + size[2]), et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.ThreeSize.getValue().equals(et.getCalculateType())) {
            return this.sizeJug(et.getOperateSign(), size[0] + size[1] + size[2], et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.ActualWeight.getValue().equals(et.getCalculateType())) {
            return this.sizeJug(et.getOperateSign(), req.getWeight(), et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Volume_Weight.getValue().equals(et.getCalculateType())) {
            if (req.getCoefficient() == null || req.getCoefficient() == 0) return false;
            //体积重 = 长*宽*高 / 体积重系数
            float f = size[0] * size[1] * size[2] / req.getCoefficient();
            return this.sizeJug(et.getOperateSign(), f, et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Billing_Weight.getValue().equals(et.getCalculateType())) {
            if (req.getCoefficient() == null || req.getCoefficient() == 0) return false;
            //计费重 = 体积重 和实重的最大值
            float f = size[0] * size[1] * size[2] / req.getCoefficient();
            return this.sizeJug(et.getOperateSign(), Math.max(req.getWeight(), f), et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Volume.getValue().equals(et.getCalculateType())) {//1立方英尺CBF = 1728 英寸 1立方米CBM = 1000000厘米
            return this.sizeJug(et.getOperateSign(), size[0] * size[1] * size[2] / (StaticDict.OMP_UnitMeasurement.Cm.getValue().equals(sizeUnit) ? 1000000 : 1728), et.getStartValue(), et.getEndValue());
        } else if (StaticDict.Sc_Calculate_Type.Country.getValue().equals(et.getCalculateType())) {
            if (StringUtils.isBlank(req.getCountryRegionCodes())) return false;
            if (StaticDict.Rule_Operate_Sign_Contain.Contain.getValue().equals(et.getOperateSign())) {
                //包含
                for (String s : req.getCountryRegionCodes().split(",")) {
                    if (!et.getCountryRegionCodes().contains(s)) return false;
                }

            } else if (StaticDict.Rule_Operate_Sign_Contain.NotContain.getValue().equals(et.getOperateSign())) {
                //除外
                for (String s : req.getCountryRegionCodes().split(",")) {
                    if (et.getCountryRegionCodes().contains(s)) return false;
                }
            }

//            return this.sizeJug(et.getOperateSign(), req.getWeight(), et.getStartValue(), et.getEndValue());
        }
        return true;
    }


    public boolean sizeJug(Integer operateSign, Float reqLength, Float startValue, Float endValue) {
        if (StaticDict.Rule_Operate_Sign.Greater_Than.getValue().equals(operateSign)) {
            //大于
            return reqLength > startValue;
        } else if (StaticDict.Rule_Operate_Sign.Less_Than.getValue().equals(operateSign)) {
            return reqLength < startValue;
        } else if (StaticDict.Rule_Operate_Sign.Equal.getValue().equals(operateSign)) {
            return reqLength.equals(startValue);
        } else if (StaticDict.Rule_Operate_Sign.Greater_Equal.getValue().equals(operateSign)) {
            return reqLength >= startValue;
        } else if (StaticDict.Rule_Operate_Sign.Less_Equal.getValue().equals(operateSign)) {
            return reqLength <= startValue;
        } else if (StaticDict.Rule_Operate_Sign.Between.getValue().equals(operateSign)) {
            return reqLength >= startValue && reqLength <= endValue;
        }
        return true;
    }

}
